use crate::{configuration, ApiError, ApiResult, ToError};
use bb8::{Pool, PooledConnection};
use bb8_redis::RedisConnectionManager;
use log::info;
use redis::AsyncTypedCommands;
use std::sync::LazyLock;
use std::time::Duration;

/// 创建redis连接池
async fn get_pool() -> Pool<RedisConnectionManager> {
    let redis = configuration::redis();
    let url = redis.url();

    let manager = if let Some(url) = url {
        RedisConnectionManager::new(url.clone())
    } else {
        let ssl = redis.ssl();
        let protocol = if ssl { "rediss" } else { "redis" };
        let username = redis.username();
        let password = redis.password();
        let host = redis.host();
        let port = redis.port();
        let database = redis.database();
        let format = format!(
            "{}://{}:{}@{}:{}/{}",
            protocol, username, password, host, port, database,
        );
        RedisConnectionManager::new(format)
    };

    let manager = match manager {
        Ok(c) => c,
        Err(e) => panic!("redis创建连接失败：{}", e),
    };

    let pool = Pool::builder()
        .max_size(redis.max_size())
        .min_idle(redis.min_idle())
        .connection_timeout(Duration::from_secs(redis.connect_timeout() as u64))
        .idle_timeout(Duration::from_secs(redis.idle_timeout() as u64))
        .build(manager)
        .await;

    let pool = match pool {
        Ok(c) => c,
        Err(e) => panic!("redis创建连接失败：{}", e),
    };

    {
        let conn = pool.get().await;
        let mut conn = match conn {
            Ok(c) => c,
            Err(e) => panic!("获取redis连接失败: {}", e),
        };
        match conn.ping().await {
            Ok(_) => info!("redis连接成功"),
            Err(e) => panic!("redis连接失败: {}", e),
        }
    }

    pool
}

static POOL: LazyLock<Pool<RedisConnectionManager>> =
    LazyLock::new(|| futures_lite::future::block_on(get_pool()));

/// 初始化redis连接池
pub fn init() -> &'static Pool<RedisConnectionManager> {
    &POOL
}

/// 获取redis连接
pub async fn get() -> ApiResult<PooledConnection<'static, RedisConnectionManager>>
{
    POOL.get().await.to_err(|| ApiError::Biz("获取redis连接失败".into()))
}
